﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using NAnt.Core;
using NAnt.Core.Types;
using NAnt.Core.Attributes;

namespace NAntExt.Functions
{
    /// <summary>
    /// NAnt Functions for rsync.
    /// </summary>
    [FunctionSet("rsync", "Rsync")]
    public class RsyncFunctions : FunctionSetBase
    {
        #region Public Instance Constructors

        public RsyncFunctions(Project project, PropertyDictionary properties)
            : base(project, properties)
        {
        }

        #endregion Public Instance Constructors

        /// <summary>
        /// Converts a network path to a rsync daemon remote path. Converts: 
        ///     From \\foomachine\c$\temp\something TO foomachine::c/temp/something 
        ///     OR 
        ///     From \\foomachine\sharename\temp\something TO foomachine::sharename/temp/something
        /// </summary>
        /// <param name="path">The network path to convert.</param>
        /// <returns>Returns the rsync daemon remote path.</returns>
        [Function("to-remote-path")]
        public static string ToRsyncRemotePath(string path)
        {
            Match pathMatch = Regex.Match(path, @"\\\\(?<host>[^\\]+)\\(?<drive>(?<driveLetter>[A-Za-z])\$)?(?<path>.*)");
            if (pathMatch.Success)
            {
                Group hostGroup = pathMatch.Groups["host"];
                Group driveLetterGroup = pathMatch.Groups["driveLetter"];
                Group pathGroup = pathMatch.Groups["path"];

                var pathFrag = pathGroup.Value.Replace('\\', '/');

                if (driveLetterGroup.Success)
                {
                    if (!string.IsNullOrEmpty(pathFrag))
                        pathFrag = "/" + pathFrag.TrimStart('/');

                    return string.Format("{0}::{1}{2}", hostGroup.Value, driveLetterGroup.Value, pathFrag);
                }
                else
                {
                    return string.Format("{0}::{1}", hostGroup.Value, pathGroup.Value.Replace('\\', '/'));
                }
            }
            else
            {
                throw new System.ArgumentOutOfRangeException("path", path, "Path does not conform to a known syntax. Must be like \\\\host\\c$\\foo\\bar.");
            }
        }

        /// <summary>
        /// Converts a network path or local path to a rsync daemon local path. Converts:
        ///     From \\foomachine\c$\temp\something TO /cygdrive/c/temp/something 
        ///     OR 
        ///     From \\foomachine\sharename\temp\something TO /temp/something
        ///     OR 
        ///     From c:\temp\something TO /cygdrive/c/temp/something
        /// </summary>
        /// <param name="path">The network path to convert.</param>
        /// <returns>Returns the rsync daemon remote path.</returns>
        [Function("to-local-path")]
        public static string ToRsyncLocalPath(string path)
        {
            Match pathMatch = Regex.Match(path, @"(\\\\[^\\]+\\)?(?<drive>(?<driveLetter>[A-Za-z])[:$])?(?<path>.*)");
            if (pathMatch.Success)
            {
                var resultPath = new StringBuilder();
                resultPath.Append("/cygdrive/");

                Group driveLetterGroup = pathMatch.Groups["driveLetter"];
                if (driveLetterGroup.Success)
                {
                    resultPath.Append(driveLetterGroup.Value)
                        .Append("/");
                }

                Group pathGroup = pathMatch.Groups["path"];
                var pathFrag = pathGroup.Value.Replace('\\', '/').TrimStart('/');
                resultPath.Append(pathFrag);

                return resultPath.ToString();
            }
            else
            {
                throw new System.ArgumentOutOfRangeException("path", path, "Path does not conform to a known syntax. Must be like \\\\host\\c$\\foo\\bar.");
            }
        }
    }
}
